package org.platform.lwc.system.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.platform.lwc.log.annotation.ApiLog;
import org.platform.lwc.mybatis.support.Condition;
import org.platform.lwc.mybatis.support.Query;
import org.platform.lwc.redis.annotation.Lock;
import org.platform.lwc.redis.utils.RedisFuncLock;
import org.platform.lwc.redis.utils.RedisUtil;
import org.platform.lwc.system.constant.SystemConstant;
import org.platform.lwc.system.dto.*;
import org.platform.lwc.system.entity.SysUser;
import org.platform.lwc.system.service.ISysUserService;
import org.platform.lwc.system.wrapper.SysUserWrapper;
import org.platform.lwc.tool.api.R;
import org.platform.lwc.tool.auth.holder.LoginUserHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 系统用户表 前端控制器
 * </p>
 *
 * @author lwc
 * @since 2022-04-09
 */
@RestController
@RequestMapping("/system/sysUser")
public class SysUserController {


    @Autowired
    private ISysUserService userService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired(required = false)
    private RedisFuncLock redisFuncLock;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private LoginUserHolder loginUserHolder;
    /*****************************redis缓存 start**********************************/

    /**
     * redis 操作demo
     */
    public void redisTest() {
        redisUtil.set("lwc","lwc");
        System.out.println(redisUtil.get("lwc"));
    }


    /**
     * 详情 测试springCache缓存添加缓存 demo
     */
    @ApiLog
    @Cacheable(value = SystemConstant.REDIS_CACHE_NAMESPACE, key = "'sys:user:'+#userId", unless = "#result==null")
    @GetMapping("/cache")
    public R detail(@RequestParam String userId) {
        SysUser byId = userService.getById(userId);
        return R.data(byId);
    }

    /**
     * 修改密码 测试springCache缓存 清除 demo
     */
    @CacheEvict(value = SystemConstant.REDIS_CACHE_NAMESPACE, key = "'sys:user:'+#dto.userId")
    @GetMapping("/changePassword")
    public R changePassword(@Validated SysUserChangePasswordDTO dto) {
        SysUser byId = userService.getById(dto.getUserId());
        if (Objects.isNull(byId)) {
            return R.fail("用户不存在");
        }
        byId.setPassword(passwordEncoder.encode(dto.getPassword()));
        userService.updateById(byId);
        return R.success("成功修改密码！");
    }
    /*****************************redis缓存 end**********************************/



    /*****************************mybaitis start**********************************/

    /**
     * mybaitis 分页 demo
     */
    @GetMapping("/page")
    public R listPage(SysUserListPageDTO dto, Query query) {
        IPage<SysUser> pages = userService.page(
                Condition.getPage(query),
                Condition.getQueryWrapper(new SysUser())
                        .lambda()
                        .eq(StrUtil.isNotBlank(dto.getName()), SysUser::getName, dto.getName())
        );
        return R.data(SysUserWrapper.build().pageVO(pages));
    }

    /**
     * mybaitis 获取详情 demo
     */
    @GetMapping("/details")
    public R listPage(String userId) {
        SysUser byId = userService.getById(userId);
        return R.data(SysUserWrapper.build().entityVO(byId));
    }

    /**
     * mybaitis 获取列表（不分页） demo
     */
    @GetMapping("/list")
    public R list(SysUserListPageDTO dto) {
        List<SysUser> list = userService.list(Condition.getQueryWrapper(new SysUser()).lambda().eq(StrUtil.isNotBlank(dto.getName()), SysUser::getName, dto.getName()));
        return R.data(SysUserWrapper.build().listVO(list));
    }

    /**
     * mybaitis 保存 demo
     */
    @PostMapping("/save")
    public R save(SysUserAddDTO dto) {
        SysUser sysUser = new SysUser();
        BeanUtil.copyProperties(dto,sysUser);
        sysUser.setId(IdUtil.randomUUID());
        sysUser.setPassword(passwordEncoder.encode(dto.getPassword()));
        userService.save(sysUser);
        return R.success("操作成功");
    }

    /**
     * mybaitis 根据id修改（不修改密码，（mybaitis只腰属性为null，则不做修改，如果想要修改，可以在对象熟悉上加入注解标识）） demo
     */
    @PostMapping("/update")
    public R update(SysUserUpdateDTO dto) {
        SysUser sysUser = new SysUser();
        BeanUtil.copyProperties(dto,sysUser);
        sysUser.setPassword(null);
        userService.updateById(sysUser);
        return R.success("操作成功");
    }

    /**
     * 使用单机事务,保证事务的一致性 demo ( @Transactional )
     */
    @Transactional
    @PostMapping("/register")
    public R register(SysUserRegisterDTO dto) {
        userService.register(dto);
        return R.success("ok");
    }


    /*****************************mybaitis end**********************************/



    /*****************************分布式锁 start**********************************/

    /**
     * @Description: 基础锁的方法使用demo 1
     */
    @PostMapping("/test/redis/lock1")
    public R testLock(SysUserListPageDTO dto, Query query) throws Exception {
        return redisFuncLock.lock("testLock1", 0, 30000, () -> {
            //获取锁成功执行逻辑
            IPage<SysUser> pages = userService.page(
                    Condition.getPage(query),
                    Condition.getQueryWrapper(new SysUser())
                            .lambda()
                            .eq(StrUtil.isNotBlank(dto.getName()), SysUser::getName, dto.getName())
            );
            return R.data(pages);
        }, () -> {
            //获取锁失败执行逻辑
            return R.fail("获取锁失败");
        });
    }

    /**
     * @Description: 基础锁的方法使用demo2
     */
    @PostMapping("/test/redis/lock2")
    @Lock(key = "testLock2")
    public R testLock2(SysUserListPageDTO dto, Query query) {
        return null;
    }

    /**
     * @Description: 基础锁的方法使用demo3 官方用法
     */
    @PostMapping("/test/redis/lock3")
    public R testLock3(SysUserListPageDTO dto, Query query) {
        return null;
    }

    /*****************************分布式锁 end**********************************/

}
